﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml;
using System.Net;
using System.Windows.Forms;

namespace UpdatePro
{
    /// <summary>
    /// 更新核心功能
    /// </summary>
    public class UpdateCore
    {
        public delegate void ShowPrecent(int num, int finishedPrecent);

        public UpdateCore()
        {
            this.LastUpdateInfo = new UpdateInfo();
            this.NowUpdateInfo = new UpdateInfo();
            GetLastUpdateInfo();
            GetNowUpdateInfo();

        }
        public ShowPrecent showPrecent = null;

        #region Pro
        /// <summary>
        /// 用户当前版本更新信息的读取与保存
        /// </summary>
        public UpdateInfo LastUpdateInfo { get; set; }

        /// <summary>
        /// 用户新版本更新信息的读取与保存
        /// </summary>
        public UpdateInfo NowUpdateInfo { get; set; }

        /// <summary>
        /// 只读属性，标识是否需要更新
        /// </summary>
        public bool IsNeedUpdate
        {
            get
            {
                //如果上次更新时间小于当前需要更新的时间，则返回True
                if (this.LastUpdateInfo.UpdateTime < this.NowUpdateInfo.UpdateTime)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// 获取存放更新文件的临时目录
        /// </summary>
        public string tempFilePath
        {
            get
            { 
                var tempFilePath = Environment.GetEnvironmentVariable("temp")+"\\"+"updateFiles";
                if (!File.Exists(tempFilePath))
                {
                    Directory.CreateDirectory(tempFilePath);
                }
                return tempFilePath;
            }
        }
        #endregion

        #region Method

        /// <summary>
        /// 从本地获取当前版本的更新文件信息
        /// </summary>
        public void GetLastUpdateInfo()
        {
            using (XmlTextReader xmlTextReader = new XmlTextReader("UpdateList.xml"))
            {
                while (xmlTextReader.Read())
                {
                    switch (xmlTextReader.Name)
                    {
                        case "UrlAddress":
                            this.LastUpdateInfo.UpdateUrl = xmlTextReader.GetAttribute("URL");
                            break;
                        case "UpdateTime":
                            this.LastUpdateInfo.UpdateTime = Convert.ToDateTime(xmlTextReader.GetAttribute("Date"));
                            break;
                        case "Version":
                            this.LastUpdateInfo.Version = xmlTextReader.GetAttribute("VersionNum");
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// 从服务器上下载需要更新的文件列表并封装需要更新的NowUpdateInfo对象
        /// </summary>
        public void GetNowUpdateInfo()
        { 
            //下载最新的跟更新文件到临时目录
            var tempPath = this.tempFilePath+"\\UpdateList.xml";
            WebClient webClient = new WebClient();
            webClient.DownloadFile(this.LastUpdateInfo.UpdateUrl + "\\" + "UpdateList.xml", tempPath);
            //读取xml文件，并根据节点信息封装NowUpdateInfo对象
            using (XmlTextReader xmlTextReader = new XmlTextReader(tempPath))
            {
                while (xmlTextReader.Read())
                {
                    switch (xmlTextReader.Name)
                    {
                        case "UrlAddress":
                            this.NowUpdateInfo.UpdateUrl = xmlTextReader.GetAttribute("URL");
                            break;
                        case "UpdateTime":
                            this.NowUpdateInfo.UpdateTime = Convert.ToDateTime(xmlTextReader.GetAttribute("Date"));
                            break;
                        case "Version":
                            this.NowUpdateInfo.Version = xmlTextReader.GetAttribute("VersionNum");
                            break;
                        case "UpdateFile":
                            var fileName = xmlTextReader.GetAttribute("FileName");
                            var version = xmlTextReader.GetAttribute("Version");
                            var contentLength= xmlTextReader.GetAttribute("ContentLength");
                            this.NowUpdateInfo.FileList.Add(new string[] { fileName, version, contentLength,"0%" });
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        /// <summary>
        /// 下载需要更新的文件到本地，并在前端同步展示下载进度
        /// </summary>
        public void DownLoadUpdateFileList()
        {
            List<string[]> fileList = this.NowUpdateInfo.FileList;
            string updateFileUrl = this.NowUpdateInfo.UpdateUrl;
            for (int i = 0; i < fileList.Count; i++)
            {
                //要下载的文件名
                var fileName = fileList[i][0];
                //需要下载的文件地址
                var fileUrl = updateFileUrl + "\\" + fileName;
                //var fileUrl = @"C:\Users\GJQ\Desktop\Test" + "\\" + fileName;
                //获取服务器的资源
                WebRequest request = WebRequest.Create(fileUrl);
                WebResponse response = request.GetResponse();
                using (Stream stream = response.GetResponseStream())
                {
                    //在线读取以及连接的远程文件，并基于委托反馈文件下载的进度
                    long fileLength = response.ContentLength;//获取响应对象的数据长度
                    //long aaa = stream.Length;
                    byte[] readerBuffer = new byte[fileLength];
                    //每一次读取开始的位置
                    int startPosition = 0;
                    //每一次读取的总数
                    int readCount = 10000;
                    //剩余的总数
                    int allCount = readerBuffer.Length;
                    while (allCount > 0)
                    {
                        Application.DoEvents();//表示在一个线程中同时处理其他事件（没有该语句，同步更新的百分比无法实现）
                        if (allCount < readCount) readCount = allCount;
                        //每一次读取读入缓冲区中的总字节数
                        var downLoadByte = stream.Read(readerBuffer, startPosition, readCount);
                        if (downLoadByte == 0) break;
                        allCount -= downLoadByte;
                        startPosition += downLoadByte;
                        //计算完成的百分比:这里必须转换成高精度的去计算
                        float part = (float)startPosition / 1024;
                        float total = (float)readerBuffer.Length / 1024;
                        int precent = Convert.ToInt32((part / total) * 100);
                        //基于委托展示下载进度
                        showPrecent(i, precent);
                    }
                    //临时保存地址
                    var savePath = this.tempFilePath + "\\" + fileName;
                    //将文件流写入文件
                    FileStream fs = new FileStream(savePath, FileMode.OpenOrCreate, FileAccess.Write);
                    fs.Write(readerBuffer, 0, readerBuffer.Length);
                    fs.Close();
                    Console.WriteLine($"第{i}个文件下载完成：" + fileUrl);
                }
            }
        }

        /// <summary>
        /// 将下载到临时目录的文件拷贝到执行目录下
        /// </summary>
        public bool FileCopy()
        {
            var fileList = Directory.GetFiles(this.tempFilePath);
            foreach (var item in fileList)
            {
                var fileName = Path.GetFileName(item);
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                File.Copy(item, fileName);
            }
            return true;
        }



        #endregion

    }
}
